﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		TypeExtensions.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 //   File:            TypeExtensions.cs
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion
 
namespace System.Reflection
{
	#region Usings

	using System.ComponentModel;
	using System.Globalization;
	using System.Linq;
	using System.Text;

	#endregion

	/// <summary>
	/// 	Defines static methods to manipulates System.Type types.
	/// 	All methods are also defined as .NET extension methods.
	/// </summary>
	public static class TypeExtensions
	{
		/// <summary>
		/// 	Returns a <see cref = "System.String" /> that represents this instance.
		/// 	Use 's' for ShortString, 'sn' for ShortNameString.
		/// </summary>
		/// <param name = "type">The type.</param>
		/// <param name = "format">The format.</param>
		/// <returns>
		/// 	A <see cref = "System.String" /> that represents this instance.
		/// </returns>
		public static String ToString ( this Type type , String format )
		{
			switch ( format.ToLower () )
			{
				case "sn":
					return type.ToShortNameString ();

				case "s":
					return type.ToShortString ();

				default:
					throw new ArgumentOutOfRangeException ( "format" );
			}
		}

		/// <summary>
		/// 	Returns a string rapresentation of the given System.Type composed 
		/// 	only by the type name (including the namespace) and the assembly name.
		/// 	The built string is compatible with a .net fully qualified type name
		/// </summary>
		/// <param name = "type">The type to build the string for.</param>
		/// <returns>A string representing the given type.</returns>
		public static String ToShortString ( this Type type )
		{
			String tName = type.FullName;
			String aName = type.Assembly.GetName ().Name;

			if ( String.Equals ( aName , "mscorlib" , StringComparison.OrdinalIgnoreCase ) )
			{
				return String.Format ( CultureInfo.InvariantCulture , "{0}" , tName );
			}
			else
			{
				return String.Format ( CultureInfo.InvariantCulture , "{0}, {1}" , tName , aName );
			}
		}

		/// <summary>
		/// 	Returns a string rapresentating the name of the given
		/// 	System.Type (without namespaces).
		/// </summary>
		/// <param name = "type">The type to build the string for.</param>
		/// <returns>A string representing the name of the given type.</returns>
		public static String ToShortNameString ( this Type type )
		{
			if ( type.IsGenericType )
			{
				string name = type.Name.Substring ( 0 , type.Name.Length - 2 );
				Type[] arguments = type.GetGenericArguments ();
				string argumentsName = arguments.Aggregate ( new StringBuilder () , ( r , s ) =>
				                                                                    	{
				                                                                    		r.AppendFormat ( "{0}, " , s.ToShortNameString () );

				                                                                    		return r;
				                                                                    	} )
					.ToString ()
					.TrimEnd ( ',' , ' ' );

				return String.Format ( "{0}<{1}>" , name , argumentsName );
			}

			return type.Name;
		}

		/// <summary>
		/// 	Determines whether the specified type a descendant of the given T type.
		/// 	This generic method is a shortcut for the Type.IsAssignableFrom( Type )
		/// 	method.
		/// </summary>
		/// <typeparam name = "T">The supposed base type.</typeparam>
		/// <param name = "type">The type to inspect.</param>
		/// <returns>
		/// 	<c>true</c> if the specified type inherits from the T type; otherwise, <c>false</c>.
		/// </returns>
		public static Boolean Is< T > ( this Type type )
		{
			return typeof ( T ).IsAssignableFrom ( type );
		}

		/// <summary>
		/// 	Gets the attribute.
		/// </summary>
		/// <typeparam name = "T"></typeparam>
		/// <param name = "pd">The pd.</param>
		/// <returns>The instance of the attribute</returns>
		public static T GetAttribute< T > ( this PropertyDescriptor pd ) where T : Attribute
		{
			return ( pd.Attributes [ typeof ( T ) ] as T );
		}

		/// <summary>
		/// 	Gets the attribute.
		/// </summary>
		/// <typeparam name = "T"></typeparam>
		/// <param name = "instance">The instance.</param>
		/// <returns>The instance of the attribute</returns>
		public static T GetAttribute< T > ( this object instance ) where T : Attribute
		{
			return Attribute.GetCustomAttribute ( instance.GetType () , typeof ( T ) ) as T;
		}
	}
}
